package lib

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"reflect"

	"gitee.com/zibianqu/fyzdb/lib/localtime"
	"gitee.com/zibianqu/fyzdb/lib/snowid"
	"gitee.com/zibianqu/fyzdb/lib/str"

	"github.com/mitchellh/mapstructure"
)

const (
	// 时间格式化
	TimeFormat = localtime.TimeFormat
	// 日期格式
	DateFormat = localtime.DateFormat
)

var (
	// 字符串处理
	Str    = str.Str{}
	MySnow = snowid.NewSnowFlake(0, 0)
)

type (
	// 时间处理
	LocalTime = localtime.LocalTime
)

func ThrowError(err error) {
	if err != nil {
		// fmt.Println("【FYZDB】:", err)
		panic(err)
	}
}

// 三元表达式
func If(condition bool, trueVal, falseVal interface{}) interface{} {
	if condition {
		return trueVal
	}
	return falseVal
}

// 获取唯一id
func UniqueId() int64 {
	id, err := MySnow.NextId()
	if err != nil {
		log.Fatal(err)
	}
	return id
}

// 美化打印
func PrettyPrint(v interface{}) {
	b, err := json.Marshal(v)
	if err != nil {
		log.Fatal(b)
		return
	}
	var out bytes.Buffer
	err = json.Indent(&out, b, "", "")
	if err != nil {
		log.Println(v)
		return
	}
	log.Println(out.String())
}

func FormatPrint(data any) {
	b, err := json.Marshal(data)
	if err != nil {
		log.Println("%+v", data)
	}
	var out bytes.Buffer
	err = json.Indent(&out, b, "", "    ")
	if err != nil {
		log.Println(fmt.Sprintf("%+v", data))
	}
	log.Println(out.String())
}

// param  只有一位参数只能是结构体转map
// param 两个参数，其中第二个参数类型为string，为结构体转map，第一个参数为结构体，第二个参数为TagName
// 如果第二个参数类型不为string， 则互相转换
// param 当为三个参数时，第一个参数为结构体，第二个参数为map类型，第三个参数为string类型TagName
func Map0Struct(param ...any) any {
	length := len(param)
	if length < 1 {
		panic("please input param!")
	}
	s1 := param[0]
	//s1vf := reflect.ValueOf(s1)
	var s2 any = nil
	var s3 any = nil
	var dest any = nil
	var tagName = ""
	var destMap = make(map[string]any)
	if length > 1 {
		s2 = param[1]
	}
	s2vf := reflect.ValueOf(s2)
	if length > 2 {
		s3 = param[2]
	}
	s3vf := reflect.ValueOf(s3)
	// 默认
	dest = s2
	if length == 1 {
		dest = destMap
	}
	if length == 2 && s2vf.Kind() == reflect.String {
		tagName = s2.(string)
		dest = destMap
	}
	if length == 3 && s3vf.Kind() == reflect.String {
		tagName = s3.(string)
		dest = s2
	}
	if tagName != "" || length == 1 {
		/*if s1vf.Kind() != reflect.Ptr && s1vf.Kind() != reflect.Struct {
			panic("param error!")
		}
		if s1vf.Kind() == reflect.Ptr {
			s1RealVf := reflect.ValueOf(s1vf.Elem())
			if s1RealVf.Kind() != reflect.Struct {
				panic("param error!")
			}
		}*/
	}
	// @link https://www.cnblogs.com/shix0909/p/15655432.html
	decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
		WeaklyTypedInput: true,
		Result:           &dest,
		TagName:          tagName,
	})
	if err != nil {
		panic(err)
	}
	decoder.Decode(s1)
	return dest
}

func Force2Str(v any) string {
	return fmt.Sprintf("%v", v)
}
